package com.xlh.service.conclude.impl;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import com.xlh.common.ResultEnum;
import com.xlh.dao.conclude.ext.ConcludeCheckMapperExt;
import com.xlh.dao.conclude.helper.ConcludeCheckMapperHelper;
import com.xlh.dao.conclude.helper.ConcludeCheckSubMapperHelper;
import com.xlh.dao.conclude.helper.ConcludeScoreMapperHelper;
import com.xlh.dao.conclude.helper.ConcludeSubCourseMapperHelper;
import com.xlh.dto.conclude.*;
import com.xlh.enums.conclude.LikedSysFunkEnum;
import com.xlh.exception.common.GlobalException;
import com.xlh.pojo.conclude.ConcludeCheck;
import com.xlh.pojo.conclude.ConcludeCheckSub;
import com.xlh.pojo.conclude.ConcludeSubCourse;
import com.xlh.service.conclude.ConcludeCheckService;
import com.xlh.util.BeanUtil;
import com.xlh.vo.conclude.CheckListInfoVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;

@Service
public class ConcludeCheckServiceImpl implements ConcludeCheckService {


    @Autowired
    private ConcludeCheckMapperHelper concludeCheckMapperHelper;

    @Autowired
    private ConcludeCheckSubMapperHelper concludeCheckSubMapperHelper;

    @Autowired
    private ConcludeSubCourseMapperHelper concludeSubCourseMapperHelper;

    @Autowired
    private ConcludeScoreMapperHelper concludeScoreMapperHelper;



    @Override
    public List<CheckListInfoVO> list( Long concludeId) {
        // 1. 分页查询相关信息
        List<CheckListInfoVO> listVo = Lists.newArrayList();
        List<ConcludeCheck> baseRecord = concludeCheckMapperHelper.findByCondition(concludeId);
        // 未查询进行返回
        if(CollectionUtil.isEmpty(baseRecord)){
            return listVo;
        }
        List<Long> checkIds = baseRecord.stream().map(ConcludeCheck::getId).collect(Collectors.toList());
        List<ConcludeCheckSub> subRecords = concludeCheckSubMapperHelper.findByCheckIds(checkIds);
        Map<Long, List<ConcludeCheckSub>> subRecordsByCheckId = subRecords.stream().collect(Collectors.groupingBy(ConcludeCheckSub::getCheckId));

        for (ConcludeCheck concludeCheck : baseRecord) {
            CheckListInfoVO transform = BeanUtil.transform(CheckListInfoVO.class, concludeCheck);
            Long checkId = concludeCheck.getId();
            List<ConcludeCheckSub> concludeCheckSubs = subRecordsByCheckId.get(checkId);
            String subStr = "";
            if(ObjectUtil.isNotNull(concludeCheckSubs)){
                subStr = concludeCheckSubs.stream().map(ConcludeCheckSub::getName).collect(Collectors.joining(","));
            }
            transform.setSubStrs(subStr);
            listVo.add(transform);
        }
        return listVo;
    }

    @Override
    @Transactional
    public Long add(ConcludeCheckAddDTO dto) {

        if(ObjectUtil.isNull(dto)){
            throw new GlobalException(ResultEnum.BAD_REQUEST);
        }
        List<ConcludeCheck> existRecords = checkNameUniqueCheck(dto, null);
        checkSubNameUniqueCheck(dto);
        checkSubFullMark(dto);

        List<ConcludeCheckSubAddDTO> concludeCheckSubs = dto.getConcludeCheckSubs();
        // 校验不能超过10条
        if( CollectionUtil.isNotEmpty(existRecords)){
            if(existRecords.size() >= 10){
                throw new  GlobalException(ResultEnum.MORE_THEN_MAX_RECORD);
            }
        }
        ConcludeCheck concludeCheck = BeanUtil.transform(ConcludeCheck.class, dto);
        concludeCheckMapperHelper.insert(concludeCheck);

        addCheckSub(concludeCheck.getId(), concludeCheckSubs);

        return  concludeCheck.getId();
    }

    /**
     * 检查考核分项名称唯一
     * @param dto
     */
    private void checkSubNameUniqueCheck(ConcludeCheckAddDTO dto) {
        // 校验考核分项名称唯一
        List<ConcludeCheckSubAddDTO> subRecords = dto.getConcludeCheckSubs();
        Map<String, List<String>> subNameMap = subRecords.stream().map(ConcludeCheckSubAddDTO::getName).collect(Collectors.groupingBy(str -> str));
        Collection<List<String>> values = subNameMap.values();
        Optional<List<String>> repeatedSubName = values.stream().filter(subNames -> subNames.size() > 1).findAny();

        // 考核分项名称不能重复
        repeatedSubName.ifPresent( repeatedSubNames -> {
            throw new GlobalException(ResultEnum.UNIQUE_SUB_CHECK_NAME);
        });
    }

    /**
     * 校验考核项名称唯一
     * @param dto
     * @return
     */
    private List<ConcludeCheck> checkNameUniqueCheck(ConcludeCheckAddDTO dto, Long filterId) {

        String checkName = dto.getName();
        List<ConcludeCheck> existRecords = concludeCheckMapperHelper.findByConcludeId(dto.getConcludeId());
        if(CollectionUtil.isNotEmpty(existRecords)){
            if(ObjectUtil.isNotNull(filterId)){
                existRecords = existRecords.stream()
                        .filter(concludeCheck -> !concludeCheck.getId().equals(filterId))
                        .collect(Collectors.toList());
            }
            Optional<String> anyRecord = existRecords.stream().map(ConcludeCheck::getName).filter(tableCheckName -> checkName.equals(tableCheckName)).findAny();
            // 校验考核项名称唯一
            anyRecord.ifPresent(str -> {
                throw new GlobalException(ResultEnum.UNIQUE_CHECK_NAME);
            });
        }
        return existRecords;
    }

    /**
     * 新增checkId
     * @param checkId
     * @param concludeCheckSubs
     */
    private void addCheckSub(Long checkId, List<ConcludeCheckSubAddDTO> concludeCheckSubs) {
        for (ConcludeCheckSubAddDTO concludeCheckSub : concludeCheckSubs) {

            ConcludeCheckSub subInfo = BeanUtil.transform(ConcludeCheckSub.class, concludeCheckSub);
            subInfo.setCheckId(checkId);
            concludeCheckSubMapperHelper.insertBatch(Lists.newArrayList(subInfo));
        }
    }


    @Override
    @Transactional
    public Long update(ConcludeCheckAddDTO dto) {

        Long checkId = dto.getId();
        if(ObjectUtil.isNull(checkId)){
            throw new GlobalException(ResultEnum.NOT_FOUND_CHECK);
        }
        // 1. 校验考核项唯一
        checkNameUniqueCheck(dto, dto.getId());
        // 2. 校验考核分项名称唯一
        checkSubNameUniqueCheck(dto);

        checkSubFullMark(dto);

        ConcludeCheck concludeCheck = BeanUtil.transform(ConcludeCheck.class, dto);
        concludeCheckMapperHelper.updateBatch(Lists.newArrayList(concludeCheck));

        List<ConcludeCheckSubAddDTO> insertDtos = dto.getConcludeCheckSubs().stream()
                    .filter(concludeCheckSub -> ObjectUtil.isNull(concludeCheckSub.getId()))
                    .collect(Collectors.toList());

        List<ConcludeCheckSubAddDTO> updateDtos = dto.getConcludeCheckSubs().stream()
                .filter(concludeCheckSub -> ObjectUtil.isNotNull(concludeCheckSub.getId()))
                .collect(Collectors.toList());

        List<ConcludeCheckSub> concludeCheckSubs = BeanUtil.batchTransform( ConcludeCheckSub.class ,dto.getConcludeCheckSubs());

        Map<Boolean, List<ConcludeCheckSub>> collect = concludeCheckSubs.stream()
                .collect(Collectors.partitioningBy(concludeCheckSub -> ObjectUtil.isNull(concludeCheckSub.getId())));

        List<ConcludeCheckSub> updateRecords = collect.get(false);
        List<Long> updateRecordId = updateRecords.stream().map(ConcludeCheckSub::getId).collect(Collectors.toList());

        //2. 筛选出已经删除的记录 从成绩表中清除
        removeIsDeleteRecord(checkId, updateRecordId);
        // 更新考核分项记录
        updateCheckSub(updateDtos);
        // 插入考核分项记录
        addCheckSub( checkId , insertDtos );

        return checkId;
    }

    /**
     * 检查考核分项的满分比重
     * @param dto
     */
    private void checkSubFullMark(ConcludeCheckAddDTO dto) {

        List<ConcludeCheckSubAddDTO> concludeCheckSubs = dto.getConcludeCheckSubs();
        Optional<BigDecimal> reduce = concludeCheckSubs.stream().map(ConcludeCheckSubAddDTO::getWeight).reduce(NumberUtil::add);

        if(reduce.isPresent()){
            BigDecimal fullMark = reduce.get();
            int compareResult = fullMark.compareTo(new BigDecimal(100));
            if(compareResult != 0){
                throw new GlobalException(ResultEnum.NOT_FULL_WEIGHT);
            }
        }else{
            throw new GlobalException(ResultEnum.NOT_FULL_WEIGHT);
        }
    }

    /**
     * \
     * @param checkId
     * @param updateRecordId
     */
    private void removeIsDeleteRecord(Long checkId, List<Long> updateRecordId) {
        List<ConcludeCheckSub> dataRecords = concludeCheckSubMapperHelper.findByCheckIds(Lists.newArrayList(checkId));

        List<ConcludeCheckSub> isDelRecord = dataRecords.stream()
                .filter(dataRecord -> !updateRecordId.contains(dataRecord.getId()))
                .collect(Collectors.toList());
        // 删除考核分项表
        deleteSubRecord(isDelRecord);

    }

    /**
     * 更新考核分项记录
     * @param updateDtos
     */
    private void updateCheckSub(List<ConcludeCheckSubAddDTO> updateDtos) {

        for (ConcludeCheckSubAddDTO updateDto : updateDtos) {

            // 关联课程目标的课程Id
            ConcludeCheckSub concludeCheckSubs = BeanUtil.transform(ConcludeCheckSub.class, updateDto);
            concludeCheckSubMapperHelper.updateBatchWithSys(Lists.newArrayList(concludeCheckSubs));
        }
    }


    /**
     * 删除考核分项
     * @param checkSubs
     */
    private void deleteSubRecord(List<ConcludeCheckSub> checkSubs) {

        if(CollectionUtil.isNotEmpty(checkSubs)){
            concludeCheckSubMapperHelper.delete(checkSubs);
        }
        // 删除中间表数据
        List<Long> subIds = checkSubs.stream().map(ConcludeCheckSub::getId).collect(Collectors.toList());

        if(CollectionUtil.isNotEmpty(checkSubs)){

            concludeSubCourseMapperHelper.deleteBySubId(subIds);
            // 删除学生关联的考核分项成绩
            concludeScoreMapperHelper.deleteBySubId(subIds);
        }
    }

    @Override
    public void setWeight(List<ConcludeCheckWeightDTO> dtos) {

        if(CollectionUtil.isEmpty(dtos)){
            throw new GlobalException(ResultEnum.NOT_FOUND_CHECK);
        }
        Long id = dtos.get(0).getId();
        if(ObjectUtil.isNull(id)){
            throw new GlobalException(ResultEnum.NOT_FOUND_ClASS);
        }
        // 1. 进行逻辑过滤
        ConcludeCheck checkInfo = concludeCheckMapperHelper.getById(id);
        List<ConcludeCheck> concludeChecksInTable = concludeCheckMapperHelper.findByCondition(checkInfo.getConcludeId());
        List<Long> recordCheckIds = concludeChecksInTable.stream().map(ConcludeCheck::getId).collect(Collectors.toList());
        List<Long> updateRecords = dtos.stream().map(ConcludeCheckWeightDTO::getId).collect(Collectors.toList());

        // 2. 要被删除的记录
        List<Long> deleteCheckId = recordCheckIds.stream().filter(recordCheckId -> !updateRecords.contains(recordCheckId)).collect(Collectors.toList());
        if(CollectionUtil.isNotEmpty(deleteCheckId)){
            for (Long checkId : deleteCheckId) {
                ConcludeParamDTO concludeParamDTO = new ConcludeParamDTO();
                concludeParamDTO.setId(checkId);
                delete(concludeParamDTO);
            }
        }
        List<ConcludeCheckWeightDTO> filterResult = dtos.stream().filter(dto -> ObjectUtil.isNotNull(dto.getWeight())).collect(Collectors.toList());
        if(CollectionUtil.isNotEmpty(filterResult)){
            checkWeight(filterResult);
        }
        // 设置考核项权重值
        List<ConcludeCheck> concludeChecks = BeanUtil.batchTransform(ConcludeCheck.class, dtos);
        concludeCheckMapperHelper.updateBatchWeightIsNull(concludeChecks);

    }

    /**
     * 考核项权重值的删除
     * @param dto
     */
    @Override
    public void delete(ConcludeParamDTO dto) {

        Long checkId = dto.getId();
        // 删除考核项数据
        concludeCheckMapperHelper.delete(Lists.newArrayList(new ConcludeCheck( checkId )));
        // 要删除的考核分项权重
        List<ConcludeCheckSub> checkSubs = concludeCheckSubMapperHelper.findByCheckIds(Lists.newArrayList(checkId));
        // 执行考核分项 及关联逻辑删除
        deleteSubRecord(checkSubs);
    }

    @Override
    public ConcludeCheckDetailDTO detail(Long checkId) {

        // 装载考核分项信息
        ConcludeCheck concludeCheck = concludeCheckMapperHelper.getById(checkId);
        if(ObjectUtil.isNull(concludeCheck)){
            throw new GlobalException(ResultEnum.NOT_FOUND_CHECK);
        }
        ConcludeCheckDetailDTO detailDTO = BeanUtil.transform(ConcludeCheckDetailDTO.class, concludeCheck);
        // 装载考核分项详情
        List<ConcludeCheckSub> subInfo = concludeCheckSubMapperHelper.findByCheckIds(Lists.newArrayList(checkId));
        List<ConcludeCheckSubAddDTO> concludeCheckSubs = Lists.newArrayList();

        for (ConcludeCheckSub concludeCheckSub : subInfo) {
            // 查询关联的课程项
            ConcludeCheckSubAddDTO subDTO = BeanUtil.transform(ConcludeCheckSubAddDTO.class, concludeCheckSub);
            concludeCheckSubs.add(subDTO);
        }
        detailDTO.setConcludeCheckSubs(concludeCheckSubs);

        return detailDTO;
    }

    /**
     * 查询关联系统信息
     * @return
     */
    @Override
    public List<Map<String, Object>> findLinkSysInfo() {

        LikedSysFunkEnum[] values = LikedSysFunkEnum.values();
        List<Map<String, Object>> result = Lists.newArrayList();

        for (LikedSysFunkEnum value : values) {
            Map<String, Object> stringObjectMap = cn.hutool.core.bean.BeanUtil.beanToMap(value);
            result.add(stringObjectMap);
        }

        return result;
    }

    /**
     * 当前权重项相加必须等于百分之百
     * @param dtos
     */
    private void checkWeight(List<ConcludeCheckWeightDTO> dtos) {

        Optional<BigDecimal> sum = dtos.stream().map(ConcludeCheckWeightDTO::getWeight).reduce(NumberUtil::add);
        Supplier<BigDecimal> supplier = () -> new BigDecimal("0");
        if(NumberUtil.compare(sum.orElseGet(supplier).doubleValue(), 100d) != 0){
            throw new GlobalException(ResultEnum.NOT_FULL_WEIGHT);
        }
    }

}
